package com.tbit.main.controller;


import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.tbit.main.common.JsonResult;
import com.tbit.main.constant.MapConstant;
import com.tbit.main.constant.PreventDuplication;
import com.tbit.main.constant.RedisConstant;
import com.tbit.main.constant.SysConstant;
import com.tbit.main.exception.BaseException;
import com.tbit.main.pojo.*;
import com.tbit.main.service.*;
import com.tbit.main.util.Assert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 挪车日志
 *
 * @author Leon
 * 2019年1月23日 下午3:51:50
 */
@Slf4j
@RestController
@RequestMapping("/moveLog")
public class MoveLogController {
    @Autowired
    private MoveLogService moveLogService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private MachineOccupyService machineOccupyService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private StockMachineService stockMachineService;

    /**
     * 分组统计
     */
    @RequestMapping("/groupByTime")
    public JsonResult groupByTime(String token, Integer accountId, Boolean isValid, String startTime, String endTime,
                                  @RequestParam(value = "regionId", required = false) List<Integer> regionId,
                                  @RequestParam(value = "machineType", required = false) Integer machineType) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        Assert.notNull(isValid, "Machine.move.isValid.notNull");
        Assert.hasLength(startTime, "System.startTime.notNull");
        Assert.hasLength(endTime, "System.endTime.notNull");
        Assert.notNull(accountId, "AccountUser.agentId.notNull");


        List<MoveLogSta> moveLogStas = moveLogService.groupByTime(accountId, accountUserToken.getAccountUserType(),
                accountUserToken.getAccountUserId(), isValid, startTime, endTime, regionId, machineType);

        return JsonResult.succ(moveLogStas);
    }

    /**
     * 查询详细
     */
    @RequestMapping("/getByTime")
    public JsonResult getByTime(Integer accountId, Integer userMainId, Boolean isValid, String startTime, String endTime,
                                @RequestParam(value = "userCode", required = false) String userCode,
                                @RequestParam(value = "regionId", required = false) List<Integer> regionId,
                                @RequestParam(value = "machineType", required = false) Integer machineType) {

        Assert.notNull(isValid, "Machine.move.isValid.notNull");
        Assert.hasLength(startTime, "System.startTime.notNull");
        Assert.hasLength(endTime, "System.endTime.notNull");
        Assert.notNull(accountId, "AccountUser.agentId.notNull");

        List<MoveLog> moveLogs = moveLogService.getByTime(accountId, userMainId, isValid, startTime, endTime, userCode, regionId, machineType);

        return JsonResult.succ(moveLogs);
    }

    /**
     * 根据id查询
     */
    @RequestMapping("/getById")
    public JsonResult getById(String token, Integer moveLogId, Integer mapType) {
        Assert.notNull(moveLogId, "Machine.move.id.notNull");

        if (mapType == null) {
            mapType = SysConstant.GOOGLE;
        }

        MoveLog moveLog = moveLogService.getById(moveLogId);

        if (moveLog != null) {
            calibrateService.calMoveLog(moveLog, MapConstant.MAP_ORI, mapType);

            /**计算挪车距离*/
            if (moveLog.getEndLon() != null && moveLog.getEndLat() != null) {
                Integer distance = historyService.getMileageByMachineNOAndTime(moveLog.getMachineNO(), moveLog.getStartTime(), moveLog.getEndTime());
                moveLog.setDistance(distance);
            }
        }

        return JsonResult.succ(moveLog);
    }

    /**
     * 挪车
     */
    @RequestMapping("/move")
    @PreventDuplication(expireSeconds = 3)
    public JsonResult move(String token, String userCode, Integer parkPointId,
                           @RequestParam(value = "mapType", required = false) Integer mapType,
                           @RequestParam(value = "lon", required = false) Double lon,
                           @RequestParam(value = "lat", required = false) Double lat) {
        AccountUser accountUserToken = tokenService.getAccount(token);
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        if (mapType == null) {
            mapType = MapConstant.MAP_GOOGLE;
        }

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**是否是运维占用*/
        MachineOccupy machineOccupy = machineOccupyService.getByMachineId(machine.getMachineId());
        if (machineOccupy != null && !machineOccupy.getAccountUserId().equals(accountUserToken.getAccountUserId())) {
            throw new BaseException("WorkOrder.occupy.notOperate");
        }

        /**是否是运维占用*/
        String moveLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_MOVE + machine.getMachineNO());
        MoveLog moveLogCache = JSONObject.parseObject(moveLogString, MoveLog.class);
        if (moveLogCache != null && !moveLogCache.getUserMainId().equals(accountUserToken.getAccountUserId())) {
            throw new BaseException("WorkOrder.occupy.notOperate");
        }

        /**是否是未出库车辆*/
        List<Integer> machineIds = new LinkedList<>();
        machineIds.add(machine.getMachineId());
        List<Integer> stockMachineIds = stockMachineService.getAccountIdByMachineId(machine.getAccountId(), machineIds);
        if (stockMachineIds != null && !stockMachineIds.isEmpty()) {
            throw new BaseException("StockMachine.is.operate");
        }

        MoveLog moveLog = moveLogService.move(accountUserToken, machine.getMachineNO(), parkPointId, lon, lat, mapType);

        return JsonResult.succ(moveLog);
    }

    /**
     * 批量调度
     */
    @RequestMapping("/moveBatch")
    @PreventDuplication(expireSeconds = 3)
    public JsonResult moveBatch(String token, RequestParameter requestParameter) throws Exception {
        AccountUser accountUserToken = tokenService.getAccount(token);

        if (requestParameter.getMapType() == null) {
            requestParameter.setMapType(MapConstant.MAP_GOOGLE);
        }

        Assert.notNull(requestParameter.getUserCodes(), "Machine.userCode.notNull");

        moveLogService.moveBatch(accountUserToken, requestParameter.getUserCodes(), requestParameter.getParkPointId(), requestParameter.getLon(), requestParameter.getLat(), requestParameter.getMapType());

        return JsonResult.succ();
    }

    /**
     * 获取批量调度车辆编号
     */
    @RequestMapping("/getBatchUserCodePower")
    public JsonResult getBatchUserCodePower(String token) {
        AccountUser accountUser = tokenService.getAccount(token);
        List<String> userCode = new LinkedList<>();
        String key = RedisConstant.REDIS_BATCH_MOVE + accountUser.getAccountUserId();
        try {
            userCode = redisService.getList(key);
        } catch (SerializationException e) {
            redisService.del(key);
        }
        List<Map<String, Object>> faultOrAbnormalList = new LinkedList<>();
        List<Map<String, Object>> list = new LinkedList<>();
        if (CollUtil.isNotEmpty(userCode)) {
            List<Machine> machines = machineService.getByUserCodes(userCode);
            Map<String, Integer> machineMap = new HashMap<>();
            Map<Integer, Integer> machineBorrowMap = new HashMap<>();
            Map<Integer, Integer> machineStatuseMap = new HashMap<>();
            Map<Integer, Map<String, List<String>>> machineFaultAndAbnormalMap = new HashMap<>();
            if (CollUtil.isNotEmpty(machines)) {
                for (Machine machine : machines) {
                    machineMap.put(machine.getUserCode(), machine.getMachineId());
                }

                List<MachineBorrow> machineBorrows = machineBorrowService.getByMachineIds(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
                for (MachineBorrow machine : machineBorrows) {
                    machineBorrowMap.put(machine.getMachineId(), 1);
                }

                List<MachineStatus> machineStatuses = machineStatusService.getByMachineIdBatch(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
                for (MachineStatus machine : machineStatuses) {
                    machineStatuseMap.put(machine.getMachineId(), machine.getSocPercent());
                }
                //获取车辆异常、故障
                machineFaultAndAbnormalMap = machineService.getMachineFaultAndAbnormal(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
            }

            for (String code : userCode) {
                // 车辆不存在删除缓存
                if (!machineMap.containsKey(code)) {
                    moveLogService.delCache(code);
                } else {
                    Map<String, List<String>> faultAndAbnormalMap = machineFaultAndAbnormalMap.get(machineMap.get(code));
                    Map<String, Object> map = new HashMap<>();
                    map.put("userCode", code);
                    map.put("inUse", machineBorrowMap.get(machineMap.get(code)) == null ? 0 : 1);
                    map.put("socPercent", machineStatuseMap.get(machineMap.get(code)));
                    map.put("abnormal", MapUtils.isNotEmpty(faultAndAbnormalMap) ? faultAndAbnormalMap.get("abnormal") : null);
                    map.put("fault", MapUtils.isNotEmpty(faultAndAbnormalMap) ? faultAndAbnormalMap.get("fault") : null);
                    //故障或异常的车辆排在前面
                    if (Objects.nonNull(map.get("abnormal")) || Objects.nonNull(map.get("fault"))){
                        faultOrAbnormalList.add(map);
                    }else {
                        list.add(map);
                    }
                }
            }
        }
        //故障或异常的车辆排在前面
        faultOrAbnormalList.addAll(list);
        return JsonResult.succ(faultOrAbnormalList);
    }

    /**
     * 获取批量调度车辆编号
     */
    @RequestMapping("/getBatchUserCode")
    public JsonResult getBatchUserCode(String token) {
        AccountUser accountUser = tokenService.getAccount(token);
        List<String> userCode = new LinkedList<>();
        try {
            userCode = redisService.getList(RedisConstant.REDIS_BATCH_MOVE + accountUser.getAccountUserId());
        } catch (SerializationException e) {
            log.error(e.getMessage(), e);
            redisService.del(RedisConstant.REDIS_BATCH_MOVE + accountUser.getAccountUserId());
        }

        return JsonResult.succ(userCode);
    }

    /**
     * 删除
     *
     * @param userCode 车辆编号
     */
    @RequestMapping("/DEL")
    public JsonResult del(String userCode) {
        Machine machine = machineService.getByUseCode(userCode);

        if (machine != null) {
            /**自动上锁*/
            moveLogService.moveLock(machine, "取消挪车自动上锁");
        }

        moveLogService.delCache(userCode);

        return JsonResult.succ();
    }
}